function _Cell(staVal) {

	let value = 0;
	let opened = false;
	let marked = false;

	if (staVal) {
		value = -1;
	}

	return {
		isOpened: () => {
			return opened;
		},
		getValue: () => {
			return value;
		},
		open: () => {
			if (marked || opened) return false;

			if (value === -1) {
				return false;
			} else {
				opened = true;
				return value === 0;
			}
		},
		setWarning: () => {
			if (value === -1 || value === 8) return;
			value += 1;
		},
		isMine: () => {
			return value === -1;
		},
		cencel: () => {
			marked = false;
			return staVal;
		},
		mark: () => {
			if (!opened) {
				marked = true;
			}
			return staVal;
		},
		isMarked: () => {
			return marked;
		}
	};
}

function _Board(width, height, count) {

	let found = 0;
	let size = width * height;
	let close = size - count;
	let _board = new Array(size);

	{
		let map = new Array(size).fill(false);
		for (let i = 0; i < count;) {
			let num = Math.trunc(Math.random() * size);
			if (!map[num]) {
				map[num] = true;
				i++;
			}
		}

		for (let i = 0; i < size; i++) {
			_board[i] = _Cell(map[i]);
		}
		// 分开来写是因为要先全部初始化好 _board 再设置雷
		for (let i = 0; i < size; i++) {
			if (map[i]) {
				setMine(i);
			}
		}
	}

	function setMine(at) {
		let x = at % width;
		let y = Math.trunc(at / width);

		if (y > 0) {
			if (x > 0) {
				_board[where(x - 1, y - 1)].setWarning();
			}
			_board[where(x, y - 1)].setWarning();
			if (x < width - 1) {
				_board[where(x + 1, y - 1)].setWarning();
			}
		}

		if (x > 0) {
			_board[where(x - 1, y)].setWarning();
		}
		if (x < width - 1) {
			_board[where(x + 1, y)].setWarning();
		}
		if (y < height - 1) {
			if (x > 0) {
				_board[where(x - 1, y + 1)].setWarning();
			}
			_board[where(x, y + 1)].setWarning();
			if (x < width - 1) {
				_board[where(x + 1, y + 1)].setWarning();
			}
		}
	}

	function where(x, y) {
		return y * width + x;
	}

	return {
		getValue: (x, y) => {
			return _board[where(x, y)].getValue();
		},
		isOpened: (x, y) => {
			return _board[where(x, y)].isOpened();
		},
		open: (x, y) => {
			let at = _board[where(x, y)];
			if (at.isMine()) return false;
			if (!at.isOpened()) {
				close--;
			}
			return at.open();
		},
		where: where,
		isMine: (x, y) => {
			return _board[where(x, y)].isMine();
		},
		isMarked: (x, y) => {
			return _board[where(x, y)].isMarked();
		},
		mark: (x, y) => {
			let at = _board[where(x, y)];
			at.mark();
			if (at.isMine()) {
				found++;
			}
		},
		cancel: (x, y) => {
			let at = _board[where(x, y)];
			at.cencel();
			if (at.isMine()) {
				found--;
			}
		},
		isWin: () => {
			return found === count || close === 0; // 都找到了，或者都翻开了
		}
	};
}

function pressEvent(width, height, table, count) {

	let board = _Board(width, height, count);
	const alerts = ['', '１', '２', '３', '４', '５', '６', '７', '８'],
		markVal = '?', bombedVal = '※', bombVal = '〇', mistake = '×';

	function gameOver(x, y) {
		let where = board.where(x, y);

		for (let i = 0; i < height; i++) { // 列（y）
			for (let j = 0; j < width; j++) { // 行（x）
				let index = i * width + j;
				let td = table[index];
				if (index === where) {
					td.innerHTML = bombedVal;
					td.className += " bombed";
				} else if (board.isMarked(j, i) && !board.isMine(j, i)) {
					td.innerHTML = mistake;
					td.className += " bombed";
				} else if (!board.isMarked(j, i) && board.isMine(j, i)) {
					td.innerHTML = bombVal;
				}
			}
		}

		setTimeout(() => {
			if (confirm("你踩到雷了！\n是否再来一局？")) {
				createStage(width, height, count);
			} else {
			}
		}, 10);
	}

	function open(x, y) {

		if (x < 0 || x > width - 1 || y < 0 || y > height - 1) return;
		if (board.isOpened(x, y)) return;

		let td = table[board.where(x, y)];
		td.className = "mouse_down";

		let index = board.getValue(x, y);
		td.innerHTML = alerts[index];
		td.className += " board_" + index;

		if (board.open(x, y)) {

			open(x - 1, y - 1);
			open(x - 1, y);
			open(x - 1, y + 1);
			open(x, y - 1);
			open(x, y + 1);
			open(x + 1, y - 1);
			open(x + 1, y);
			open(x + 1, y + 1);
		}
	}

	function mark(x, y) {

		let td = table[board.where(x, y)];
		td.className = "default";
		let isMarked = board.isMarked(x, y);
		if (isMarked) {
			board.cancel(x, y);
			td.innerHTML = alerts[0];
		} else {
			board.mark(x, y);
			td.innerHTML = markVal;
		}
	}

	return {
		left: (x, y) => {
			if (board.isOpened(x, y)) return;

			if (board.isMine(x, y)) {
				gameOver(x, y);
			} else {
				open(x, y);
			}
		},
		middle: (x, y) => {
			if (!board.isOpened(x, y)) return;
			open(x, y);
		},
		right: (x, y) => {
			if (board.isOpened(x, y)) return;
			mark(x, y);
		},
		isWin: () => {
			if (board.isWin()) {
				showResult("赢", width, height, count);
			}
		}
	};
}